/*
author:yiliangwu880
	you can get more refer from https ://gitee.com/yiliangwu880/CppUtility.git

使用方式：参考用！
属性修改，同步到客户端。
解决问题：游戏人物属性改变，需要同步到客户端。 避免每次修改属性写同步代码，每次发送大量属性内容。
设计目的：用户只需要修改属性， 内部自动同步到客户端。
用参考代码的方式提供使用，不同项目需要修改。

例如：
	class Player
	{
	public :
		std::unordered_map<AttrTypeUint32, uint32> m_dirtyMapUint32;//记录脏数据，需要下次更新给客户端

		SyncUint32 hp=0;  //某个状态数据，变化需要通知客户端
		//SyncUint32 hp(AttrTypeUint32.HP, m_dirtyMapUint32);	//有空需要优化成这样初始化。 构造函数做 m_dirtyMapUint32（类包装一层）对象是否初始化检查，加强健壮。

		Player()
		{
			hp.Init(AttrTypeUint32.HP, m_dirtyMapUint32);
		}

		void Update()//定时调用
		{
			if (!m_dirtyMapUint32.empty())
			{
				Msg msg;
				for (auto&& [k, v] : m_dirtyMapUint32)
				{
					//set to msg
					...
				}
				//send msg to client
				...
				m_dirtyMapUint32.clear();
			}
		}
	};
*/
#include <functional>
#include <limits>
#include <queue>
#include <string>
#include <vector>
#include <unordered_map>
#include <iterator>  
#include <type_traits>
#include <memory>
#include <array>
#include <set>
#include <unordered_set>
#include "log_def.h"
#include "typedef.h"

enum class AttrTypeUint32
{
	///////////////////////////////要求从HP到ATTR_MAX必须连续的/////////////////////////////////////////
	HP=0,
	MANA,
	DEF,
	FIGHT_MAX,
	ATTR_MAX,
	///////////////////////////////要求从HP到ATTR_MAX必须连续的/////////////////////////////////////////

	STR,
	MONEY,
};

enum class AttrTypeUint64
{
	STR,
	MONEY,
	T1,
	T2,
	T3,
	MAX,

};


enum class AttrTypeBool
{
	IS_DEAD,
	MONEY,

};

enum class AttrTypeDouble
{
	SPEED,
	MONEY,
};



inline bool operator<(const AttrTypeUint64& a, const AttrTypeUint64& b)
{
	return (int)a < (int)b;
}

inline bool operator<(const AttrTypeUint32& a, const AttrTypeUint32& b)
{
	return (int)a < (int)b;
}

inline bool operator<(const AttrTypeBool& a, const AttrTypeBool& b)
{
	return (int)a < (int)b;
}

inline bool operator<(const AttrTypeDouble& a, const AttrTypeDouble& b)
{
	return (int)a < (int)b;
}

//SyncNum<T> 操作类似 T类型, 但能支持自动远程同步数据功能
template<class AttrType, class T>
class SyncNum
{
	std::unordered_map<AttrType, T>* m_dirtyMap = nullptr; //记录修改过的数据
	AttrType m_type = (AttrType)0;
	T m_num = T();

public:
	SyncNum(){}
	SyncNum(AttrType type, std::unordered_map<AttrType, T>& m, T num = T())
	{
		m_type = type;
		m_dirtyMap = &m;
		m_num = num;
	}
	//注意：m的生存期必须比this长。
	void Init(AttrType type, std::unordered_map<AttrType, T>& m)
	{
		m_type = type;
		m_dirtyMap = &m;
	}
	SyncNum & operator=(T n)
	{
		m_num = n;
		L_COND(m_dirtyMap, *this);
		(*m_dirtyMap)[m_type] = m_num;
		return *this;
	}

	SyncNum& operator+=(T n)
	{
		m_num += n;
		L_COND(m_dirtyMap, *this);
		(*m_dirtyMap)[m_type] = m_num;
		return *this;
	}
	SyncNum& operator-=(T n)
	{
		m_num -= n;
		L_COND(m_dirtyMap, *this);
		(*m_dirtyMap)[m_type] = m_num;
		return *this;
	}
	// 前置++运算符
	SyncNum& operator++()
	{
		++m_num;
		L_COND(m_dirtyMap, *this);
		(*m_dirtyMap)[m_type] = m_num;
		return *this;
	}
	// 前置--运算符
	SyncNum& operator--()
	{
		--m_num;
		L_COND(m_dirtyMap, *this);
		(*m_dirtyMap)[m_type] = m_num;
		return *this;
	}
	//bool operator<(T n)const
	//{
	//	return m_num < n;
	//}
	//不需要定义operator>=等操作符号了。 这里会自动转换为 T类型。再比较
	operator T() const
	{
		return m_num;
	}

	void SetDirty(bool bDirty = true)
	{
		L_COND_V(m_dirtyMap);
		if (bDirty)
		{
			(*m_dirtyMap)[m_type] = m_num;
		}
		else
		{
			(*m_dirtyMap).erase(m_type);
		}
	}


	AttrType Type()const
	{
		return m_type;
	}
};


using SyncUint32 = SyncNum<AttrTypeUint32, uint32>;
using SyncUint64 = SyncNum<AttrTypeUint64, uint64>;
using SyncBool = SyncNum<AttrTypeBool, bool>;
using SyncDouble = SyncNum<AttrTypeDouble, double>;

//索引值 表示 AttrType. 快速查找
//目的 Overwrite []操作符. 
template<class AttrType, class T, uint32 Size>
struct SyncArray: public std::array<SyncNum<AttrType,T>, Size>
{
	SyncArray()
	{
	}	
	SyncArray(std::array<AttrType, Size> types, std::unordered_map<AttrType, T>& m)
	{
		for (uint32 i = 0; i < Size; i++)
		{
			this->at(i).Init(types[i], m);
		}
	}

	//根据startType初始化，要求用户自己保证 [startType，Size) 范围内的 AttrType 是有效连续的
	//startType可以>0 
	void Init(AttrType startType, std::unordered_map<AttrType, T>& m)
	{
		for (uint32 i = 0; i < Size; i++)
		{
			this->at(i).Init((AttrType)((int)startType+i), m);
		}
	}

	SyncNum<AttrType, T>& operator[](AttrType type) //Overwrite
	{
		//或者这里做偏移 idx = type + offset
		return this->at((uint32)type);;
	}

	SyncNum<AttrType, T>& operator[](size_t type) //Overwrite
	{
		//或者这里做偏移 idx = type + offset
		return this->at((uint32)type);;
	}
};

template<uint32 Size>
using SyncUint32Array = SyncArray<AttrTypeUint32, uint32, Size>;
template<uint32 Size>
using SyncUint64Array = SyncArray<AttrTypeUint64, uint64, Size>;
template<uint32 Size>
using SyncBoolArray = SyncArray<AttrTypeBool, bool, Size>;
template<uint32 Size>
using SyncDoubleArray = SyncArray<AttrTypeDouble, double, Size>;

